

#include "Scheduler.h"
#include "Coroutine.h"
#include "Hook.h"
#include "Thread.h"
#include <cassert>
#include <cstddef>
#include <iostream>
#include <memory>

static bool debug = false;
namespace zepco {


// 当前线程的调度器，同一个调度器下的所有线程共享同一个实例
static thread_local Scheduler *t_scheduler = nullptr;


Scheduler *Scheduler::GetThis() {
    return t_scheduler;
}

void Scheduler::SetThis() {
    t_scheduler = this;
}

Scheduler::Scheduler(size_t threads, bool use_caller, const std::string &name)
    : m_name(name), m_userCaller(use_caller) {
    assert(threads > 0 && Scheduler::GetThis() == nullptr);
    SetThis();
    Thread::SetName(m_name);
    if (use_caller) { // 使用主线程当作工作线程

        threads --;

        Zephyr::GetThis(); // 创建主协程

        // 创建调度协程 子协程
        m_schedulerZephyr = std::make_shared<Zephyr>(std::bind(&Scheduler::run, this), 0, false); //false -> 该调度协程退出后将返回主协程
        Zephyr::SetSchedulerZephyr(m_schedulerZephyr.get());

        // 获取主线程id
        m_rootThread = Thread::GetThreadID();
        m_threadIds.push_back(m_rootThread);
    }

    m_threadCount = threads;
    if (debug)
        std::cout << "Schduler::Schduler() Success\n";
}

Scheduler::~Scheduler() {
    assert(m_stoping == true);
    if (GetThis() == this) {
        t_scheduler = nullptr;
    }
    if (debug)
        std::cout << "Schduler::~Scheduler() Success\n";
}

bool Scheduler::stopping() {
    std::lock_guard<std::mutex> lock(m_mtx);
    return m_stoping && m_task.empty() && m_activateThreadCount == 0;
}

void Scheduler::start() {
    // 通过start创建的线程不会创建主协程 调度协程
    std::lock_guard<std::mutex> lock(m_mtx);
    if (m_stoping) {
        std::cerr << "Scheduler is stopped\n";
        return;
    }
    assert(m_threads.empty());
    m_threads.resize(m_threadCount);
    for (size_t i = 0; i < m_threadCount; i++) {
        m_threads[i] = std::make_shared<Thread>(
                           std::bind(&Scheduler::run, this), m_name + "_" + std::to_string(i));
        m_threadIds.push_back(m_threads[i]->getID());
    }
    if (debug)
        std::cout << "Schduler::start() Success\n";
}

void Scheduler::run() {
    int thread_id = Thread::GetThreadID();
    if (debug)
        std::cout << "Schduler::run() starts in thread: " << thread_id << std::endl;

    // TODO: set hook enable function
    set_hook_enable(true);

    SetThis();

    if (thread_id != m_rootThread) { // 不是主线程 还没有创建主协程，调度协程
        Zephyr::GetThis();
    }

    std::shared_ptr<Zephyr> idle_zephry = std::make_shared<Zephyr>(std::bind(&Scheduler::idle, this));
    SchedulerTask task;

    while (true) {
        task.reset();
        bool tickle_me = false; // 是否唤醒了其他线程进行任务调度
        {
            std::lock_guard<std::mutex> locl(m_mtx);
            auto it = m_task.begin();
            while (it != m_task.end()) {
                if (it->thread != -1 && it->thread != thread_id) {
                    it ++;
                    tickle_me = true;
                    continue;
                }
                assert (it->zephyr || it->callback);
                task = *it;
                m_task.erase(it);
                m_activateThreadCount ++;
                break;
            }

            tickle_me = tickle_me || (it != m_task.end());
        }

        if (tickle_me) { // 唤醒
            // TODO:
            tickle();
        }

        if (task.zephyr) { //  协程任务
            {
                std::lock_guard<std::mutex> locl(task.zephyr->m_mtx);
                if (task.zephyr->getState() != Zephyr::TERM) {
                    task.zephyr->resume();
                }
            }
            m_activateThreadCount --;
            task.reset();
        } else if (task.callback) { // 回调任务
            std::shared_ptr<Zephyr> cb_zephyr = std::make_shared<Zephyr>(task.callback, 0);
            {
                std::lock_guard<std::mutex> lock(cb_zephyr->m_mtx);
                cb_zephyr->resume();
            }
            m_activateThreadCount --;
            task.reset();
        } else { // 无任务执行空闲协程
            if (idle_zephry->getState() == Zephyr::TERM) {
                if (debug)
                    std::cout << "Schduler::run() ends int thread: " << thread_id << std::endl;
                break;
            }
            m_idleThreadCount ++;
            idle_zephry->resume();
            m_idleThreadCount --;
        }
    }
}

void Scheduler::tickle() {
    // TODO:
}

void Scheduler::idle() {
    while (!stopping()) {
        if (debug)
            std::cout << "Schduler::idle(), sleeping in thread: " << Thread::GetThreadID() << std::endl;
        sleep(1);
        Zephyr::GetThis()->yield();
    }
}


void Scheduler::stop() {
    if (debug)
        std::cout << "Schduler::stop() starts in thread: " << Thread::GetThreadID() << std::endl;

    if (stopping()) {
        return;
    }

    m_stoping = true;

    // 如果use caller，那只能由caller线程发起stop
    if (m_userCaller) {
        assert(GetThis() == this);
    } /* else {
        assert(GetThis() != this);
    } */

    for (size_t i = 0; i < m_threadCount; i++) {
        tickle();
    }

    if (m_schedulerZephyr) {
        tickle();
    }

    if (m_schedulerZephyr) {
        m_schedulerZephyr->resume();
        if (debug)
            std::cout << "m_schedulerZephyr ends in thread: " << Thread::GetThreadID() << std::endl;
    }

    std::vector<std::shared_ptr<Thread>> thrs;
    {
        std::lock_guard<std::mutex> lock(m_mtx);
        thrs.swap(m_threads);
    }

    for (auto &i : thrs) {
        i->join();
    }
    if (debug)
        std::cout << "Schduler::stop() ends in thread: " << Thread::GetThreadID() << std::endl;
}


}